
package com.phevos.common.util;


import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.phevos.common.dbpool.BasicConnectionPool;
import com.phevos.common.dbpool.exception.DBPoolException;

public class SerialManager
{

    private static final Logger logger = LoggerFactory.getLogger(SerialManager.class.getName());

    /**
     * ���кŶ�������� �����ݿ��serials��ÿһ���¼��ʼ�����кŶ���
     * 
     * @throws SQLException
     * @throws SerialException
     */
    private SerialManager() throws SQLException, SerialException
    {

        serialObjects = new HashMap();
        String sql = "select serialname,intervalnum from serials";
        Connection con = null;
        try
        {
            con = com.phevos.common.dbpool.BasicConnectionPool.getInstance().getConnection();
        }
        catch (Exception e)
        {
            throw new SerialException("getConnection error:" + e.toString());
        }
        Statement stmt = con.createStatement();
        ResultSet rs = stmt.executeQuery(sql);
        String name = null;
        int intervalNum = 0;
        while (rs.next())
        {
            name = rs.getString(1);
            intervalNum = rs.getInt(2);
            serialObjects.put(name, new SerialObject(name, intervalNum));
        }

        if (rs != null)
        {
            try
            {
                rs.close();
            }
            catch (Exception e)
            {
                logger.error("",e);
            }
        }
        if (stmt != null)
        {
            try
            {
                stmt.close();
            }
            catch (Exception e)
            {
                logger.error("",e);
            }
        }

        com.phevos.common.dbpool.BasicConnectionPool.getInstance().returnConnection(con);

    }

    // Ψһʵ��
    private static SerialManager instance = null;

    // ���б���������кŶ���
    private HashMap serialObjects;

    /**
     * ��ȡ���������Ψһʵ��
     * 
     * @return
     * @throws SQLException
     * @throws SerialException
     */
    public synchronized static SerialManager getInstance() throws SQLException, SerialException
    {
        if (instance == null)
        {
            instance = new SerialManager();
        }
        return instance;
    }

    /**
     * ������к���ƻ�ȡָ�����кŶ������һ��������к�
     * 
     * @param name ��Ӧ��ݿ��serials�е�һ���¼ �����ڣ�������һ���¼
     * @return
     * @throws SQLException
     * @throws SerialException
     * @throws DBPoolException
     */
    public synchronized int getNextId(String name) throws SQLException, SerialException,
            DBPoolException
    {
        try{
        SerialObject serialObject = (SerialObject)serialObjects.get(name);
        if (serialObject == null)
        {
            addNewSerialObject(name);
            serialObject = (SerialObject)serialObjects.get(name);
        }
        return serialObject.getNextSN();
        }catch(Throwable t)
        {          
            t.printStackTrace();
            logger.error("xxxxxxxxxx",t);
            throw new SerialException("name is"+name,t);
        }
    }

    private void addNewSerialObject(String name) throws SQLException
    {
        String sql = "insert into serials values('" + name + "',1,10)";
        Connection conn = null;
        Statement stmt = null;
        try
        {
            conn = com.phevos.common.dbpool.BasicConnectionPool.getInstance().getConnection();
            stmt = conn.createStatement();
            //stmt.executeQuery(sql);
            stmt.execute(sql);
            serialObjects.put(name, new SerialObject(name, 10));
        }
        catch (Exception e)
        {
            e.printStackTrace();
            logger.error("xx:::",e);
            throw new SQLException(e.getMessage());
        }
        finally
        {
            if (stmt != null)
            {
                try
                {
                    stmt.close();
                }
                catch (Exception e)
                {
                    logger.error("",e);
                }
            }
            com.phevos.common.dbpool.BasicConnectionPool.getInstance().returnConnection(conn);
        }

    }
}

/**
 * ���кŶ��� ��ݿ��serials�е�ÿһ���¼��Ӧһ�����кŶ���
 * 
 * @author �Գ���
 * @version 1.0
 */
final class SerialObject extends Object
{
    // �����кŶ�������֣�Ҳ�����кŶ����Ψһ��ʶ
    private String name = null;

    // �����кŶ������һ�δ���ݿ��ȡ����ʼ���к�
    private int initSN = -1;

    // �����кŶ������һ�δ���ݿ��ȡ�Ľ������к�
    private int endSN = -1;

    // �����кŶ�����һ��������к�
    private int curSN = 0;

    // ÿ�δ���ݿ��м��ص����к��ж��ٸ�
    private int intervalNum;

    private static final Logger logger = LoggerFactory.getLogger(SerialManager.class.getName());

    SerialObject(String argName, int interval)
    {
        name = argName;
        intervalNum = interval;
    }

    /**
     * ��ȡ�����кŶ������һ��������к�
     * 
     * @return
     * @throws SerialException 
     * @throws SQLException 
     * @throws SQLException
     * @throws SerialException
     */
    final synchronized int getNextSN() throws SQLException, SerialException 
    {
        if (curSN < endSN)
        {
            return curSN++;
        }
        else
        { // ��һ�δ���������ʱ,curSN=0,endSN=-1,������ݿ��г�ʼ�����
            initSN = loadNextIdFromDB();
            endSN = initSN + intervalNum;
            curSN = initSN;
            return curSN++;
        }
    }

    /**
     * ����ݿ��л�ȡ�����кŶ������һ��������к�
     * 
     * @return
     * @throws SQLException
     * @throws SerialException modify by zhaoch on
     *             20040617:��returnConnection�ŵ�finally��,�������ڻ�ȡ��l��ʧ��ʱ,���ܴ���l�ӳ�����
     * @see BasicConnectionPool
     */
    private final int loadNextIdFromDB() throws SQLException, SerialException
    {
        String sql = "select nextvalue from serials where serialname='" + name + "'";
        log(sql);
        Connection conn = null;
        int nextId = 0;
        Statement stmt = null;
        ResultSet rs = null;
        try
        {
            conn = com.phevos.common.dbpool.BasicConnectionPool.getInstance().getConnection();
            stmt = conn.createStatement();
            rs = stmt.executeQuery(sql);
            if (rs.next())
            {
                nextId = rs.getInt(1);
            }
            sql = "update serials set nextvalue=nextvalue+" + intervalNum + " where serialname='"
                    + name + "'";
            stmt.executeUpdate(sql);
        }
        catch (Throwable e)
        {
            logger.error("serialManager load nextId from DB fail",e);
            throw new SerialException("serialManager load nextId from DB fail:",e);
        }
        finally
        {
            if (rs != null)
            {
                try
                {
                    rs.close();
                }
                catch (Exception e)
                {
                    logger.error("",e);
                }
            }
            if (stmt != null)
            {
                try
                {
                    stmt.close();
                }
                catch (Exception e)
                {
                    logger.error("",e);
                }
            }
            com.phevos.common.dbpool.BasicConnectionPool.getInstance().returnConnection(conn);
        }
        return nextId;

    }

    private static void log(String str)
    {
        // ###//###logger.debug(str);
    }
}
